HomeActivity启动流程(launcher)

0. 写在前面的话

上一篇讲了各种Service是在何时启动的,最后提到了关于HomeActivity的启动。HomeActivity作为Android系统启动后第一个加载的Activity,今天就来分析下其启动流程。
其实还有个时序图的,但是太大了,截图也不全,等下次直接上传,方便自己查看。
暂时的规划先是Activity的启动流程,通过这个又会涉及到进程间通信——Binder机制,接着Activity启动后,布局是如何绘制到屏幕上,View的事件是如何分发的?通过这条线来慢慢整理这两年多我对Android的理解,加深自己的印象。


1. ActivityManagerService.systemReady(new Runnable())做了什么?

我们先来看下这个方法的代码:

public void systemReady(final Runnable goingCallback) {
    synchronized(this) {
        //mSystemReady默认为false,所以第一次调用这个方法时不会执行goingCallback.run()
        if (mSystemReady) {
            if (goingCallback != null) {
                goingCallback.run();
            }
            return;
        }
        ......
    }
    //要杀掉的进程(启动时不允许启动的进程)
    ArrayList<ProcessRecord> procsToKill = null;
    synchronized(mPidsSelfLocked) {
        for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
            ProcessRecord proc = mPidsSelfLocked.valueAt(i);
            if (!isAllowedWhileBooting(proc.info)){
                if (procsToKill == null) {
                    procsToKill = new ArrayList<ProcessRecord>();
                }
                procsToKill.add(proc);
            }
        }
    }
    //杀掉这些进程
    synchronized(this) {
        if (procsToKill != null) {
            for (int i=procsToKill.size()-1; i>=0; i--) {
                ProcessRecord proc = procsToKill.get(i);
                Slog.i(TAG, "Removing system update proc: " + proc);
                removeProcessLocked(proc, true, false, "system update done");
            }
        }

        // Now that we have cleaned up any update processes, we
        // are ready to start launching real processes and know that
        // we won't trample on them any more.
        mProcessesReady = true;
    }
    ......
    //这里会调用Runnable的run()方法
    if (goingCallback != null) goingCallback.run();
    ......
    synchronized (this) {
        //启动常驻的应用
        startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
        mBooting = true;
        if (UserManager.isSplitSystemUser()) {
            ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
            try {
                //解禁SystemUserHomeActivity
                AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
                        UserHandle.USER_SYSTEM);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }
        }
        //开始启动HomeActivity
        startHomeActivityLocked(currentUserId, "systemReady");
        ......
    }
}

这个方法内容挺多的,首次进入是设置的Runnable不会执行,后面通过查找启动时系统不允许启动的进程,并将其kill掉。接下来启动了系统常驻应用startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE),通过使用AppGlobals.getPackageManager().setComponentEnabledSetting方法解禁SystemUserHomeActivity,其flag为PackageManager.COMPONENT_ENABLED_STATE_ENABLED,最后通过startHomeActivityLocked(currentUserId, "systemReady")来启动HomeActivity


2. startHomeActivityLocked开始启动HomeActivity

这里的代码不多,也很好理解:

boolean startHomeActivityLocked(int userId, String reason) {
    //测试模式下不用管
    if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
            && mTopAction == null) {
        // We are running in factory test mode, but unable to find
        // the factory test app, so just sit around displaying the
        // error message and don't try to start anything.
        return false;
    }
    //得到要启动Activity的Intent
    Intent intent = getHomeIntent();
    //将Intent解析成ActivityInfo
    ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
        intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
        // Don't do this if the home app is currently being
        // instrumented.
        aInfo = new ActivityInfo(aInfo);
        aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
        ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                aInfo.applicationInfo.uid, true);
        if (app == null || app.instrumentationClass == null) {
            intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
            //启动Activity
            mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
        }
    } else {
        Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
    }

    return true;
}

Intent getHomeIntent() {
    Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
    intent.setComponent(mTopComponent);
    intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
    //不是测试情况下则设置Category为Intent.CATEGORY_HOME
    if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
        intent.addCategory(Intent.CATEGORY_HOME);
    }
    return intent;
}

首先是判断当前系统是否处于测试环境,接着去获取(创建)HomeIntent,并将其解析成ActivityInfo,接下来调用ActivityStarter中的startHomeActivityLocked(intent, aInfo, reason)方法去启动HomeActivity


3. startHomeActivityLockedstartActivityLocked

我们进入ActivityStarter中可以看到startHomeActivityLocked调用了startActivityLocked方法,其中传入的参数只有IntentActivityInfo不为空,其他的都为null或者0或者false,由于大部分参数都为nullstartActivityLocked中真正执行的代码并不是很多。

void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
    mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
    //调用了参数居多的方法
    startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
            null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,
            null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
            0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
            0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
            false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
            null /*container*/, null /*inTask*/);
    if (mSupervisor.inResumeTopActivity) {
        // If we are in resume section already, home activity will be initialized, but not
        // resumed (to avoid recursive resume) and will stay that way until something pokes it
        // again. We need to schedule another resume.
        mSupervisor.scheduleResumeTopActivities();
    }
}
//这个参数是真TM的多啊
final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
        ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
        TaskRecord inTask) {
    //启动结果代码
    int err = ActivityManager.START_SUCCESS;
    
    ProcessRecord callerApp = null;
    //caller == null
    if (caller != null) {
        ......
    }
    
    final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;

    if (err == ActivityManager.START_SUCCESS) {
        ..Log..
    }

    ActivityRecord sourceRecord = null;
    ActivityRecord resultRecord = null;
    //resultTo == null
    if (resultTo != null) {
        ......
    }

    final int launchFlags = intent.getFlags();
    //Activity启动是设置的flags
    if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
        ......
    }

    ......
    
    //检查启动Activity的权限
    boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
            requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
            resultRecord, resultStack, options);
    abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
            callingPid, resolvedType, aInfo.applicationInfo);

    if (mService.mController != null) {
        try {
            // The Intent we give to the watcher has the extra data
            // stripped off, since it can contain private information.
            Intent watchIntent = intent.cloneFilter();
            abort |= !mService.mController.activityStarting(watchIntent,
                    aInfo.applicationInfo.packageName);
        } catch (RemoteException e) {
            mService.mController = null;
        }
    }

    ......

    // If we have an ephemeral app, abort the process of launching the resolved intent.
    // Instead, launch the ephemeral installer. Once the installer is finished, it
    // starts either the intent we resolved here [on install error] or the ephemeral
    // app [on install success].
    if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
        intent = buildEphemeralInstallerIntent(intent, ephemeralIntent,
                rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType,
                userId);
        resolvedType = null;
        callingUid = realCallingUid;
        callingPid = realCallingPid;

        aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
    }
    //创建了ActivityRecord,用于存储保存Activity
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
            requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
            options, sourceRecord);
    ......

    try {
        mService.mWindowManager.deferSurfaceLayout();
        //启动Activity
        err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                true, options, inTask);
    } finally {
        mService.mWindowManager.continueSurfaceLayout();
    }
    postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
    return err;
}

虽然上面的方法参数很多,但是由于大部分都为null或者0,所以真正执行的部分很少。先进行对flag的检查,我们的intent只设置了Intent.FLAG_DEBUG_TRIAGED_MISSING,所以对flag判断的部分执行也不执行。权限检查!mSupervisor.checkStartAnyActivityPermission,如果没有权限,则最终不会启动。我们要启动的是HomeActivity,所有需要的权限都有,因此创建一个ActivityRecord,用于存放Activity的信息,最后调用startActivityUnchecked执行启动过程。


4. startActivityUnchecked过程

startActivityUnchecked这个方法做了很多事情,包括了对当前的ActivitylaunchMode的设置、处理,我们要启动的是HomeActivity,所以呢,我们并不care这些东西。

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
    //初始化,这里需要注意的一点是doResume这个参数我们传过来的是true,下面会用到
    setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
            voiceInteractor);
    //设置launchMode flag
    computeLaunchingTaskFlags();

    computeSourceStack();

    mIntent.setFlags(mLaunchFlags);

    mReusedActivity = getReusableIntentActivity();

    final int preferredLaunchStackId =
            (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;

    if (mReusedActivity != null) {
        // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
        // still needs to be a lock task mode violation since the task gets cleared out and
        // the device would otherwise leave the locked task.
        if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task,
                (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                        == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
            mSupervisor.showLockTaskToast();
            Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }

        if (mStartActivity.task == null) {
            mStartActivity.task = mReusedActivity.task;
        }
        if (mReusedActivity.task.intent == null) {
            // This task was started because of movement of the activity based on affinity...
            // Now that we are actually launching it, we can assign the base intent.
            mReusedActivity.task.setIntent(mStartActivity);
        }

        // This code path leads to delivering a new intent, we want to make sure we schedule it
        // as the first operation, in case the activity will be resumed as a result of later
        // operations.
        //这里是处理launchMode为FLAG_ACTIVITY_CLEAR_TOP的情况
        if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                || mLaunchSingleInstance || mLaunchSingleTask) {
            // In this situation we want to remove all activities from the task up to the one
            // being started. In most cases this means we are resetting the task to its initial
            // state.
            final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
                    mStartActivity, mLaunchFlags);
            if (top != null) {
                if (top.frontOfTask) {
                    // Activity aliases may mean we use different intents for the top activity,
                    // so make sure the task now has the identity of the new intent.
                    top.task.setIntent(mStartActivity);
                }
                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
                //去掉用Activity的onNewIntent方法
                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                        mStartActivity.launchedFromPackage);
            }
        }

        sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);

        mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);

        if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
            ......
        }
        setTaskFromIntentActivity(mReusedActivity);

        if (!mAddingToTask && mReuseTask == null) {
            ......
        }
    }

    if (mStartActivity.packageName == null) {
        if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
            mStartActivity.resultTo.task.stack.sendActivityResultLocked(
                    -1, mStartActivity.resultTo, mStartActivity.resultWho,
                    mStartActivity.requestCode, RESULT_CANCELED, null);
        }
        ActivityOptions.abort(mOptions);
        //启动失败
        return START_CLASS_NOT_FOUND;
    }

    // If the activity being launched is the same as the one currently at the top, then
    // we need to check if it should only be launched once.
    //如果当前的Activity的launchModeFLAG_ACTIVITY_SINGLE_TOP,并且是处于任务栈的栈顶,
    //则不用启动,并调用Activity的onNewIntent方法
    final ActivityStack topStack = mSupervisor.mFocusedStack;
    final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
    final boolean dontStart = top != null && mStartActivity.resultTo == null
            && top.realActivity.equals(mStartActivity.realActivity)
            && top.userId == mStartActivity.userId
            && top.app != null && top.app.thread != null
            && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
            || mLaunchSingleTop || mLaunchSingleTask);
    if (dontStart) {
        ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
        // For paranoia, make sure we have correctly resumed the top activity.
        topStack.mLastPausedActivity = null;
        if (mDoResume) {
            mSupervisor.resumeFocusedStackTopActivityLocked();
        }
        ActivityOptions.abort(mOptions);
        if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
            // We don't need to start a new activity, and the client said not to do
            // anything if that is the case, so this is it!
            return START_RETURN_INTENT_TO_CALLER;
        }
        //调用Activity的onNewIntent方法
        top.deliverNewIntentLocked(
                mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);

        // Don't use mStartActivity.task to show the toast. We're not starting a new activity
        // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
        mSupervisor.handleNonResizableTaskIfNeeded(
                top.task, preferredLaunchStackId, topStack.mStackId);

        return START_DELIVERED_TO_TOP;
    }

    boolean newTask = false;
    final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
            ? mSourceRecord.task : null;

    // Should this be considered a new task?
    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
            && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
        newTask = true;
        setTaskFromReuseOrCreateNewTask(taskToAffiliate);

        if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
            Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }
        if (!mMovedOtherTask) {
            // If stack id is specified in activity options, usually it means that activity is
            // launched not from currently focused stack (e.g. from SysUI or from shell) - in
            // that case we check the target stack.
            updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
                    preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
        }
    } else if (mSourceRecord != null) {
        if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
            Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }

        final int result = setTaskFromSourceRecord();
        if (result != START_SUCCESS) {
            return result;
        }
    } else if (mInTask != null) {
        // The caller is asking that the new activity be started in an explicit
        // task it has provided to us.
        if (mSupervisor.isLockTaskModeViolation(mInTask)) {
            Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }

        final int result = setTaskFromInTask();
        if (result != START_SUCCESS) {
            return result;
        }
    } else {
        // This not being started from an existing activity, and not part of a new task...
        // just put it in the top task, though these days this case should never happen.
        setTaskToCurrentTopOrCreateNewTask();
    }

    mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
            mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);

    if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
        mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
    }
    if (newTask) {
        EventLog.writeEvent(
                EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
    }
    ActivityStack.logStartActivity(
            EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
    mTargetStack.mLastPausedActivity = null;

    sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);
    
    mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
    //mDoResume设置为true
    if (mDoResume) {
        ......
        final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
        if (!mTargetStack.isFocusable()
                || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                && mStartActivity != topTaskActivity)) {
            // If the activity is not focusable, we can't resume it, but still would like to
            // make sure it becomes visible as it starts (this will also trigger entry
            // animation). An example of this are PIP activities.
            // Also, we don't want to resume activities in a task that currently has an overlay
            // as the starting activity just needs to be in the visible paused state until the
            // over is removed.
            mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
            // Go ahead and tell window manager to execute app transition for this activity
            // since the app transition will not be triggered through the resume channel.
            mWindowManager.executeAppTransition();
        } else {
            //执行此方法
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                    mOptions);
        }
    } else {
        mTargetStack.addRecentActivityLocked(mStartActivity);
    }
    mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);

    mSupervisor.handleNonResizableTaskIfNeeded(
            mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId);

    return START_SUCCESS;
}

在这个方法中,我们看到了对Activity的不同的launchMode的处理,我们要启动的HomeActivity只会是启动一个新的Task,所以大部分操作还是启动其他Activity时进行的。代码里面也讲到了,我们在初始化是mDoResume传入了true,代码会执行mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);


5. 方法的各种调用直至resumeTopActivityInnerLocked

上面讲到我们会执行ActivityStackSupervisorresumeFocusedStackTopActivityLocked方法,跟进方法后会发现其又会调用ActivityStackresumeTopActivityUncheckedLocked方法,这个方法会调用自身的resumeTopActivityInnerLocked方法,在resumeTopActivityInnerLocked中,会根据当前的Activity Task中是否有需要pause的Activity,如果有先去执行pause,没有的话则去启动Activity。
大致代码

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    // Find the first activity that is not finishing.
    //这里看了很久,后来从前面的代码慢慢理清的话,这个next就是指的就是当前要启动的Activity的Record
    //这里是自己的理解,希望不会有什么差错
    final ActivityRecord next = topRunningActivityLocked();
    ......
    final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
    boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);
    if (mResumedActivity != null) {
        if (DEBUG_STATES) Slog.d(TAG_STATES,
                "resumeTopActivityLocked: Pausing " + mResumedActivity);
        //执行pause
        pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
    }
    ......
    ActivityStack lastStack = mStackSupervisor.getLastStack();
    //要启动的Activity的app是不是为空,显然是null
    if (next.app != null && next.app.thread != null) {
        ......
    } else {
        //启动
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }

    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    return true;
}

上面的代码我省略了很多,主要是先拿到最上面运行的先判断其是否为null,不为null则去判断是否需要执行pause,我们这里面是不需要执行的,在后面有个对next.app的非空判断,因为我们是第一次启动,所以并没有app,最后会执行mStackSupervisor.startSpecificActivityLocked(next, true, true)这部分代码。


6. ActivityStackSupervisor.startSpecificActivityLocked过程

这个过程就比较简单了,通过AMS去启动一个新的进程(Process)。

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);

    r.task.stack.setLaunchTime(r);
    //很明显,这里的app为null,我们需要创建新的process
    if (app != null && app.thread != null) {
        ......
    }
    //启动新的process
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}   

7. AMS启动新的进程

AMS中startProcessLocked中调用了Process.start这个方法。Process.start中调用了startViaZygote方法,接着调用zygoteSendArgsAndGetResult方法,通过socket进行通信执行ActivityThreadmain方法。
部分代码:

AMS:
private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        ......
        //去启动进程
        Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);
        ......
}
Process.java:
public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        
    }
}
private static ProcessStartResult startViaZygote(final String processClass,
                              final String niceName,
                              final int uid, final int gid,
                              final int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] extraArgs)
                              throws ZygoteStartFailedEx {
    synchronized(Process.class) {
        ......
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi)/**这里可以看到通过socket启动*/, argsForZygote);
    }
}

private static ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList<String> args)
        throws ZygoteStartFailedEx {
    try {
        
        int sz = args.size();
        for (int i = 0; i < sz; i++) {
            if (args.get(i).indexOf('\n') >= 0) {
                throw new ZygoteStartFailedEx("embedded newlines not allowed");
            }
        }

        final BufferedWriter writer = zygoteState.writer;
        final DataInputStream inputStream = zygoteState.inputStream;
        
        writer.write(Integer.toString(args.size()));
        writer.newLine();

        for (int i = 0; i < sz; i++) {
            String arg = args.get(i);
            writer.write(arg);
            writer.newLine();
        }

        writer.flush();

        // Should there be a timeout on this?
        ProcessStartResult result = new ProcessStartResult();

        // Always read the entire result from the input stream to avoid leaving
        // bytes in the stream for future process starts to accidentally stumble
        // upon.
        result.pid = inputStream.readInt();
        result.usingWrapper = inputStream.readBoolean();

        if (result.pid < 0) {
            throw new ZygoteStartFailedEx("fork() failed");
        }
        //返回结果
        return result;
    } catch (IOException ex) {
        zygoteState.close();
        throw new ZygoteStartFailedEx(ex);
    }
}

通过Zygote可以执行ActivityThread中的main方法。


8. ActivityThreadmain方法

main方法中在上面一篇中也提到过,上次SystemServer启动过程中会调用attach(true)方法,而我们通过Zygote启动的时候,会调用attach(false)这个方法。

public static void main(String[] args) {
    ......
    //主线程
    Looper.prepareMainLooper();
    
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    ......
    //一直循环,如果退出,说明程序关闭
    Looper.loop();
    ......
}
private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled();
            }
        });
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        //获取AMS的本地代理类
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            //调用AMS的attachApplication方法
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Watch for getting close to heap limit.
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        });
    } else {
       ......
    }
    ......
    ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {......});
}

上面的主要是就是通过Binder调用AMSattachApplication方法。


9. AMS的attachApplication方法

attachApplication中主要是判断当前的Process是否存在,如果存在,则需要将其kill。接着通过thread.bindApplication来将一些需要的变量初始化,进行Application初始化,调用ApplicationonCreate()方法。最后通过mStackSupervisor.attachApplicationLocked(app)方法去真正启动Activity。下面大概看下整个流程:

//这里没啥讲的,就是调用了attachApplicationLocked方法
@Override
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {

    // Find the application record that is being attached...  either via
    // the pid if we are running in multiple processes, or just pull the
    // next app record if we are emulating process with anonymous threads.
    //从进程中查找是否有,如果有的话去杀掉这个进程
    ProcessRecord app;
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            app = mPidsSelfLocked.get(pid);
        }
    } else {
        app = null;
    }

    if (app == null) {
        Slog.w(TAG, "No pending application record for pid " + pid
                + " (IApplicationThread " + thread + "); dropping process");
        EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
        if (pid > 0 && pid != MY_PID) {
            Process.killProcessQuiet(pid);
            //TODO: killProcessGroup(app.info.uid, pid);
        } else {
            try {
                //退出
                thread.scheduleExit();
            } catch (Exception e) {
                // Ignore exceptions.
            }
        }
        return false;
    }

    // If this application record is still attached to a previous
    // process, clean it up now.
    //如果当前的Application记录仍然依附到之前的进程中,则清理掉
    if (app.thread != null) {
        handleAppDiedLocked(app, true, true);
    }

    // Tell the process all about itself.

    if (DEBUG_ALL) Slog.v(
            TAG, "Binding process pid " + pid + " to record " + app);

    final String processName = app.processName;
    try {
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }

    EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);

    app.makeActive(thread, mProcessStats);
    app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
    app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
    app.forcingToForeground = null;
    updateProcessForegroundLocked(app, false, false);
    app.hasShownUi = false;
    app.debugging = false;
    app.cached = false;
    app.killedByAm = false;

    // We carefully use the same state that PackageManager uses for
    // filtering, since we use this flag to decide if we need to install
    // providers when user is unlocked later
    app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);

    mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
    //mProcessesReady这个变量在AMS的systemReady中被赋值为true,所以这里的normalMode也为true
    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    ......
    try {
        int testMode = IApplicationThread.DEBUG_OFF;
        if (mDebugApp != null && mDebugApp.equals(processName)) {
            testMode = mWaitForDebugger
                ? IApplicationThread.DEBUG_WAIT
                : IApplicationThread.DEBUG_ON;
            app.debugging = true;
            if (mDebugTransient) {
                mDebugApp = mOrigDebugApp;
                mWaitForDebugger = mOrigWaitForDebugger;
            }
        }
        String profileFile = app.instrumentationProfileFile;
        ParcelFileDescriptor profileFd = null;
        int samplingInterval = 0;
        boolean profileAutoStop = false;
        if (mProfileApp != null && mProfileApp.equals(processName)) {
            mProfileProc = app;
            profileFile = mProfileFile;
            profileFd = mProfileFd;
            samplingInterval = mSamplingInterval;
            profileAutoStop = mAutoStopProfiler;
        }
        boolean enableTrackAllocation = false;
        if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
            enableTrackAllocation = true;
            mTrackAllocationApp = null;
        }

        // If the app is being launched for restore or full backup, set it up specially
        boolean isRestrictedBackupMode = false;
        if (mBackupTarget != null && mBackupAppName.equals(processName)) {
            isRestrictedBackupMode = mBackupTarget.appInfo.uid >= Process.FIRST_APPLICATION_UID
                    && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
                            || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
                            || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
        }

        if (app.instrumentationClass != null) {
            notifyPackageUse(app.instrumentationClass.getPackageName(),
                             PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
        }
        if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
                + processName + " with config " + mConfiguration);
        ApplicationInfo appInfo = app.instrumentationInfo != null
                ? app.instrumentationInfo : app.info;
        app.compat = compatibilityInfoForPackageLocked(appInfo);
        if (profileFd != null) {
            profileFd = profileFd.dup();
        }
        ProfilerInfo profilerInfo = profileFile == null ? null
                : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
        //真正执行绑定操作是通过thread的bindApplication方法。
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode,
                mBinderTransactionTrackingEnabled, enableTrackAllocation,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat,
                getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked());
        updateLruProcessLocked(app, false, null);
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
    } catch (Exception e) {
        ......
        return false;
    }

    // Remove this record from the list of starting applications.
    mPersistentStartingProcesses.remove(app);
    if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
            "Attach application locked removing on hold: " + app);
    mProcessesOnHold.remove(app);

    boolean badApp = false;
    boolean didSomething = false;

    // See if the top visible activity is waiting to run in this process...
    //上面说到,这里为true,进入StackSupervisor的attachApplicationLocked方法去真正启动Activity
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }
    
    ......

    return true;
}


10. StackSupervisorattachApplicationLocked方法

这个方法会调用realStartActivityLocked方法,去真正启动Activity

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    boolean didSomething = false;
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            if (!isFocusedStack(stack)) {
                continue;
            }
            ActivityRecord hr = stack.topRunningActivityLocked();
            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        //真正启动Activity
                        if (realStartActivityLocked(hr, app, true, true)) {
                            didSomething = true;
                        }
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Exception in new application when starting activity "
                              + hr.intent.getComponent().flattenToShortString(), e);
                        throw e;
                    }
                }
            }
        }
    }
    if (!didSomething) {
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    }
    return didSomething;
}

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
    ......
    try {
        ......
        app.forceProcessStateUpTo(mService.mTopProcessState);
        //最主要的就是这里,也是通过Activity中的方法去启动Activity。
        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
        ......
    } catch (RemoteException e) {
        
    }
    ......
    return true;
}

讲到这里基本上启动流程就完成了,后面就是ActivityThread进行Activity的启动过程,这个下次在继续分析。


11. 总结

这里面所有的关于Activity启动,resume,pause等等都是通过ActivityThread来进行操作,而这之中又会涉及到ActivityThread将任务交给Instrumentation去处理。这个处理过程包括了与跨进程与远端的AMS进行通信,AMS又通过ActivityStarter,ActivityStackSupervisor,ActivityStack等进行处理,最终将所启动的Activity真正启动。
其实还有个时序图的,但是太大了,截图也不全,等下次直接上传,方便自己查看。
下面计划分析ActivityThread启动Activity。


12. 写在后面的话

想写关于Activity启动流程想了好久,说实话其中有一部分只能按自己的理解来解释,可能会有一些问题。但是起码自己认为是对的。嗯,这就够了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容